
#ifndef SX_MASS_SPRING_SIMULATION_RECORDER_H
#define SX_MASS_SPRING_SIMULATION_RECORDER_H

#include <sxAbstractRecorder.h>
#include <sxAbstractRecording.h>
#include <sxSimulationListener.h>
#include <sxMassSpringSimulationKeyFrame.h>
#include <sxMassSpringSimulation.h>

/* Sx Library Types. */
using Sx::Multimedia::AbstractRecorder;
using Sx::Multimedia::AbstractRecording;
using Sx::Simulation::Animation::MassSpringSimulationKeyFrame;
using Sx::Simulation::Simulations::MassSpringSimulation;

namespace Sx {
namespace Simulation {
namespace Recording {

/* 
 * Based on the definition of the MassSpringSimulationRecorder, this is the type
 * that defines the structure of the required recording. An instance of this
 * basic recording type must be provided to the Recorder upon construction. A
 * reference is used to ensure that there are no copies of the recording made,
 * unless the recorder is specifically asked to make one.
 */
typedef AbstractRecording<MassSpringSimulationKeyFrame, MassSpringSimulationKeyFrame::FrameUnit> MassSpringSimulationRecording;

/* 
 * The MassSpringSimulationRecorder provides an implementation of the abstract
 * recorder interface. This class defines how a MassSpringSimulation is used
 * to populate the mass-spring frames of a recording.
 */
class MassSpringSimulationRecorder : public AbstractRecorder<MassSpringSimulationKeyFrame, MassSpringSimulationKeyFrame::FrameUnit>, public SimulationListener {
public:
	MassSpringSimulationRecorder(const std::shared_ptr<MassSpringSimulation>& simulation, const std::shared_ptr<MassSpringSimulationRecording>& recording);
	virtual ~MassSpringSimulationRecorder();

	bool setSimulation(const std::shared_ptr<MassSpringSimulation>& simulation);

	/* 
	 * When to process a mass-spring simulation frame - Every time the
	 * provided simulation updates, a new frame will be written to the internal
	 * recording (unless recordingFrames is false). This means that for every
	 * new dt in the mass-spring simulation, there will be a new frame that
	 * stores all of the information for each mass-spring mesh.
	 */
	void postUpdate();

	/* Simulation Listener Ignored Events */
	void onConstruct();
	void preUpdate();
	void preRender();
	void postRender();
	void onReset();
	void onPause();
	void onResume();

	/* 
	 * If the simulation is destroyed then the recording will no longer be
	 * valid. This is because the minimal amount of data is stored in the
	 * recording for performance reasons.
	 */
	void onDestroy();

protected:
	/* How to process a mass-spring simulation frame */
	bool processFrame(MassSpringSimulationKeyFrame& frame);

	/* POINTER_OWNERSHIP: NO */
	std::shared_ptr<MassSpringSimulation> simulation;
};

}

}

}

#endif
